import re
import json
import jsonschema
from jsonpath_ng import parse
from datetime import datetime


class ResponseValidator:
    """响应结果验证器"""

    def __init__(self, response, expected_results):
        """
        初始化验证器
        :param response: requests.Response对象
        :param expected_results: 预期结果配置
        """
        self.response = response
        self.expected_results = expected_results
        self.actual_results = {
            'status_code': response.status_code,
            'headers': dict(response.headers),
            'body': response.json() if response.headers.get('content-type', '').startswith('application/json') else response.text,
            'response_time': response.elapsed.total_seconds() * 1000,  # 转换为毫秒
            'response_size': len(response.content),
        }
        self.extracted_variables = {}

    def validate(self):
        """
        执行所有验证
        :return: (bool, str) - (是否通过, 错误信息)
        """
        validators = [
            self._validate_status_code,
            self._validate_headers,
            self._validate_json_schema,
            self._validate_json_path,
            self._validate_regex,
            self._validate_response_time,
            self._validate_response_size,
            self._validate_numeric,
            self._validate_contains,
            self._validate_not_contains,
            self._validate_length,
            self._extract_variables
        ]

        for validator in validators:
            is_valid, message = validator()
            if not is_valid:
                return False, message

        return True, "测试通过"

    def _validate_status_code(self):
        """验证状态码"""
        if 'status_code' in self.expected_results:
            expected_code = self.expected_results['status_code']
            if self.response.status_code != expected_code:
                return False, f"状态码不匹配，期望 {expected_code}，实际 {self.response.status_code}"
        return True, ""

    def _validate_headers(self):
        """验证响应头"""
        if 'headers' in self.expected_results:
            expected_headers = self.expected_results['headers']
            for key, value in expected_headers.items():
                if key.lower() not in self.actual_results['headers'] or \
                   self.actual_results['headers'][key.lower()] != value:
                    return False, f"响应头不匹配，键 '{key}' 的值不符合预期"
        return True, ""

    def _validate_json_schema(self):
        """验证JSON Schema"""
        if 'json_schema' in self.expected_results and isinstance(self.actual_results['body'], dict):
            try:
                jsonschema.validate(
                    instance=self.actual_results['body'],
                    schema=self.expected_results['json_schema']
                )
            except jsonschema.exceptions.ValidationError as e:
                return False, f"JSON Schema验证失败: {str(e)}"
        return True, ""

    def _validate_json_path(self):
        """验证JSONPath表达式"""
        if 'json_path' in self.expected_results and isinstance(self.actual_results['body'], dict):
            for path, expected_value in self.expected_results['json_path'].items():
                try:
                    jsonpath_expr = parse(path)
                    matches = [match.value for match in jsonpath_expr.find(self.actual_results['body'])]
                    if not matches:
                        return False, f"JSONPath '{path}' 未找到匹配项"
                    if expected_value not in matches:
                        return False, f"JSONPath '{path}' 的值不符合预期"
                except Exception as e:
                    return False, f"JSONPath验证失败: {str(e)}"
        return True, ""

    def _validate_regex(self):
        """验证正则表达式"""
        if 'regex' in self.expected_results:
            body_text = self.actual_results['body'] if isinstance(self.actual_results['body'], str) \
                else json.dumps(self.actual_results['body'])
            for pattern, expected_match in self.expected_results['regex'].items():
                matches = re.findall(pattern, body_text)
                if not matches:
                    return False, f"正则表达式 '{pattern}' 未找到匹配项"
                if expected_match is not None and expected_match not in matches:
                    return False, f"正则表达式 '{pattern}' 的匹配结果不符合预期"
        return True, ""

    def _validate_response_time(self):
        """验证响应时间"""
        if 'response_time' in self.expected_results:
            expected_time = self.expected_results['response_time']
            actual_time = self.actual_results['response_time']
            
            if isinstance(expected_time, dict):
                if 'max' in expected_time and actual_time > expected_time['max']:
                    return False, f"响应时间超过最大限制，期望 <= {expected_time['max']}ms，实际 {actual_time}ms"
                if 'min' in expected_time and actual_time < expected_time['min']:
                    return False, f"响应时间低于最小限制，期望 >= {expected_time['min']}ms，实际 {actual_time}ms"
            else:
                if actual_time > expected_time:
                    return False, f"响应时间超过限制，期望 <= {expected_time}ms，实际 {actual_time}ms"
        return True, ""

    def _validate_response_size(self):
        """验证响应大小（字节）"""
        if 'response_size' in self.expected_results:
            expected_size = self.expected_results['response_size']
            actual_size = self.actual_results['response_size']
            
            if isinstance(expected_size, dict):
                if 'max' in expected_size and actual_size > expected_size['max']:
                    return False, f"响应大小超过最大限制，期望 <= {expected_size['max']}字节，实际 {actual_size}字节"
                if 'min' in expected_size and actual_size < expected_size['min']:
                    return False, f"响应大小低于最小限制，期望 >= {expected_size['min']}字节，实际 {actual_size}字节"
            else:
                if actual_size > expected_size:
                    return False, f"响应大小超过限制，期望 <= {expected_size}字节，实际 {actual_size}字节"
        return True, ""

    def _validate_numeric(self):
        """验证数值比较"""
        if 'numeric' in self.expected_results and isinstance(self.actual_results['body'], dict):
            for path, conditions in self.expected_results['numeric'].items():
                try:
                    jsonpath_expr = parse(path)
                    matches = [match.value for match in jsonpath_expr.find(self.actual_results['body'])]
                    if not matches:
                        return False, f"JSONPath '{path}' 未找到匹配项"
                    
                    value = float(matches[0])
                    for operator, expected in conditions.items():
                        if operator == 'eq' and value != expected:
                            return False, f"数值不相等，期望 {expected}，实际 {value}"
                        elif operator == 'gt' and value <= expected:
                            return False, f"数值不大于期望值，期望 > {expected}，实际 {value}"
                        elif operator == 'gte' and value < expected:
                            return False, f"数值不大于等于期望值，期望 >= {expected}，实际 {value}"
                        elif operator == 'lt' and value >= expected:
                            return False, f"数值不小于期望值，期望 < {expected}，实际 {value}"
                        elif operator == 'lte' and value > expected:
                            return False, f"数值不小于等于期望值，期望 <= {expected}，实际 {value}"
                except Exception as e:
                    return False, f"数值比较失败: {str(e)}"
        return True, ""

    def _validate_contains(self):
        """验证包含关系"""
        if 'contains' in self.expected_results:
            body_text = self.actual_results['body'] if isinstance(self.actual_results['body'], str) \
                else json.dumps(self.actual_results['body'])
            for text in self.expected_results['contains']:
                if text not in body_text:
                    return False, f"响应内容不包含预期文本: '{text}'"
        return True, ""

    def _validate_not_contains(self):
        """验证不包含关系"""
        if 'not_contains' in self.expected_results:
            body_text = self.actual_results['body'] if isinstance(self.actual_results['body'], str) \
                else json.dumps(self.actual_results['body'])
            for text in self.expected_results['not_contains']:
                if text in body_text:
                    return False, f"响应内容不应包含文本: '{text}'"
        return True, ""

    def _validate_length(self):
        """验证长度"""
        if 'length' in self.expected_results and isinstance(self.actual_results['body'], (list, dict)):
            for path, expected_length in self.expected_results['length'].items():
                try:
                    if path == '$':  # 验证根对象
                        actual_length = len(self.actual_results['body'])
                    else:
                        jsonpath_expr = parse(path)
                        matches = [match.value for match in jsonpath_expr.find(self.actual_results['body'])]
                        if not matches:
                            return False, f"JSONPath '{path}' 未找到匹配项"
                        actual_length = len(matches[0]) if isinstance(matches[0], (list, dict)) else len(str(matches[0]))
                    
                    if isinstance(expected_length, dict):
                        if 'min' in expected_length and actual_length < expected_length['min']:
                            return False, f"长度小于最小限制，路径 '{path}'，期望 >= {expected_length['min']}，实际 {actual_length}"
                        if 'max' in expected_length and actual_length > expected_length['max']:
                            return False, f"长度超过最大限制，路径 '{path}'，期望 <= {expected_length['max']}，实际 {actual_length}"
                        if 'eq' in expected_length and actual_length != expected_length['eq']:
                            return False, f"长度不等于期望值，路径 '{path}'，期望 = {expected_length['eq']}，实际 {actual_length}"
                    else:
                        if actual_length != expected_length:
                            return False, f"长度不等于期望值，路径 '{path}'，期望 {expected_length}，实际 {actual_length}"
                except Exception as e:
                    return False, f"长度验证失败: {str(e)}"
        return True, ""

    def _extract_variables(self):
        """提取变量"""
        if 'extract' in self.expected_results:
            for var_name, extractor in self.expected_results['extract'].items():
                if 'json_path' in extractor:
                    try:
                        jsonpath_expr = parse(extractor['json_path'])
                        matches = [match.value for match in jsonpath_expr.find(self.actual_results['body'])]
                        if matches:
                            self.extracted_variables[var_name] = matches[0]
                    except Exception as e:
                        return False, f"变量提取失败 '{var_name}': {str(e)}"
                elif 'regex' in extractor:
                    body_text = self.actual_results['body'] if isinstance(self.actual_results['body'], str) \
                        else json.dumps(self.actual_results['body'])
                    matches = re.findall(extractor['regex'], body_text)
                    if matches:
                        self.extracted_variables[var_name] = matches[0]
                elif 'header' in extractor:
                    header_name = extractor['header']
                    if header_name.lower() in self.actual_results['headers']:
                        self.extracted_variables[var_name] = self.actual_results['headers'][header_name.lower()]
        return True, ""

    def get_extracted_variables(self):
        """获取提取的变量"""
        return self.extracted_variables 